Adding a Command to Ruby

The instructions below detail the steps required to add a Simics runtime command to the Ruby module.

Assumptions

These instructions assume most commands are issued from the ruby/ directory of your workspace. The command added in the example assumes a single string parameter is needed as an agrument to the command.

The final version of the command will look something like this (invokeable from the Simics command line):

  ruby0.my-command "my argument"

Command Cookbook

Short Version

  1. Decide name of command, arguments, etc.
  2. Add an entry for your command to module/commands.py.

  3. Add a RUBY_COMMAND([COMMAND_NAME]) macro in module/ruby.c.

  4. Update module/ruby.c's ruby_session_set() function to check for the new command.

  5. Add a declaration of [FUNCTION_NAME] to simics/commands.h.

  6. Implement [FUNCTION_NAME] in simics/commands.C.

Detailed Version

  1. Select values for the following "variables" for your command. They will be used throughout this cookbook.
    • [FUNCTION_NAME]: Name of the function in C++ that your command will invoke. In this example, we use my_command as our [FUNCTION_NAME].

    • [COMMAND_NAME]: A double-quote encapuslated string, the name of the Simics command. In this example, we use "my-command" as our [COMMAND_NAME].

    • [ARGUMENT_NAME]: Name of the argument (or arguments) to the command. In this example, we use my_argument as our [ARGUMENT_NAME]. Note that if your command has many arguments, it should have many [ARGUMENT_NAME]s.

    • [ARGUMENT_DESCRIPTION]: A double-quote encapsulated string, describing the nature of the argument.

    • [COMMAND_DESCRIPTION_SHORT]: A double-quote encapsulated string, briefly describing the new command.

    • [COMMAND_DESCRIPTION_LONG]: A double-quote encapsulated string, describing the new command in detail.

  2. Add an entry for your command to module/commands.py. Your entry should be of the form:

       1 def [FUNCTION_NAME](obj, [ARGUMENT_NAME]):
       2     SIM_set_attribute(obj, [COMMAND_NAME], [ARGUMENT_NAME])
       3 
       4 new_command([COMMAND_NAME], [FUNCTION_NAME],
       5             args = [args(str_t, [ARGUMENT_DESCRIPTION], "?", "")],
       6             type = "multifacet commands",
       7             namespace = "ruby",
       8             short = [COMMAND_DESCRIPTION_SHORT],
       9             doc = """
      10 <b>[COMMAND_NAME]</b> [COMMAND_DESCRIPTION_LONG]
      11 """)
    
    • For example, if we substitute our "variable" definitions into the python code:
       1 def ruby_my_command(obj, my_argument):
       2     SIM_set_attribute(obj, "my-command", my_argument)
       3 
       4 new_command("my-command", ruby_my_command,
       5             args = [arg(str_t, "a string argument", "?", "")],
       6             type = "multifacet commands",
       7             namespace = "ruby",
       8             short = "a description of the command",
       9             doc = """
      10 <b>my-command</b> an example command for the Multifacet WIKI
      11 """)
    
    • Ruby's module/commands.py should provide examples of how to use parameters.

  3. Add a RUBY_COMMAND([COMMAND_NAME]) macro to the list of RUBY_COMMAND() macros in module/ruby.c. Note that module/ruby.c is a C-language file, not C++, so do not use C++ language components in module/ruby.c.

       1 ...
       2 RUBY_COMMAND( "abort-all" );   // last command already in ruby.c
       3 RUBY_COMMAND( "my-command" );  // entry for the new command
       4 ...
    
  4. Add a check to the long if/else tree in module/ruby.c's ruby_session_set() function, such that if command is identically equal to [COMMAND_NAME], then [FUNCTION_NAME] is called. Again note that module/ruby.c is a C-language file, not C++, so do not use C++ language components in module/ruby.c.

       1 ...
       2            /* Last currently-existing command */
       3 } else if (!strcmp(command, "tracer-output-file" ) ) { 
       4     char* new_filename = (char*) val->u.string;
       5     ruby_set_tracer_output_file(new_filename);
       6     return Sim_Set_Ok;
       7 
       8            /* Entry for the new command*/
       9 } else if (!strcmp(command, "my-command" ) ) { 
      10     char* my_argument = (char*) val->u.string;
      11 
      12     /* Call [FUNCTION_NAME] now */
      13     ruby_my_command( my_argument );    
      14 
      15     /* Don't forget this line! */        
      16     return Sim_Set_Ok;                         
      17 }
    
  5. Add a declaration of [FUNCTION_NAME] to simics/commands.h.

       1 ...
       2 /* old commands */
       3 void ruby_set_tracer_output_file (const char * new_filename);
       4 
       5 /* our new command */
       6 void ruby_my_command(const char * my_argument);
       7 
       8 #endif // COMMANDS_H
    
  6. Add the implementation of the command ([FUNCTION_NAME]) to simics/commands.C. simics/commands.C is a C++ language source file, and therefore you are free to use applicable C++ syntax. You are also free to invoke code elsewhere in Ruby from simics/commands.C. Our example below simply prints the contents of its parameter to the screen.

       1 
       2 /* Be sure to prefix your function name with extern "C" */
       3 extern "C"
       4 void ruby_my_command(const char * my_argument) {
       5   cout << "My argument was [" << my_argument << "] " << endl;
       6   /* 
       7    * Can make calls to Ruby here, see other functions in
       8    * commands.C for examples
       9    */
      10  
      11   return;
      12 }
      13 
    
  7. Your command should now be in-place. Recompile Ruby and test your command.

Adding a Command to Ruby (last edited 2010-02-04 16:53:07 by DanGibson)